#include <regx52.h>
#include "I2C.h"
#include "LCD1602.h"

// 定义 SDA 和 SCL 引脚
#define SHUJU SDA  // 数据线（SDA）
#define SHOU SCL   // 时钟线（SCL）

// 引脚定义（P2^0 和 P2^1）对应 SDA 和 SCL
sbit SDA = P2^0;  // 数据线（SDA）
sbit SCL = P2^1;  // 时钟线（SCL）

/**
 * @brief 启动 I2C 通信
 * 
 * 生成 I2C 协议中的起始信号（Start Condition），
 * 用于开始 I2C 数据传输。
 * 
 * @param none
 * @return none
 */
void I2C_Start()
{
    SHOU = 1;   // 将 SCL 拉高，准备开始传输
    SHUJU = 1;  // 将 SDA 拉高
    SHUJU = 0;  // 将 SDA 拉低，启动信号
    SHOU = 0;   // 将 SCL 拉低，完成启动
}

/**
 * @brief 停止 I2C 通信
 * 
 * 生成 I2C 协议中的停止信号（Stop Condition），
 * 用于结束 I2C 数据传输。
 * 
 * @param none
 * @return none
 */
void I2C_Stop()
{
    SHUJU=0;
    SHOU = 1;   // 将 SCL 拉高
    SHUJU = 1;  // 将 SDA 拉高，停止信号
}

/**
 * @brief 发送一个字节数据（8 位）
 * 
 * 通过 I2C 协议逐位发送一个字节的数据。
 * 
 * @param Data 需要发送的数据（8 位）
 * @return none
 */
void I2C_SendByte(unsigned char Data)
{
    unsigned char i = 0;

    // 逐位发送字节
    for (i = 0; i < 8; i++)
    {
        SHUJU = Data & (0x80 >> i);  // 逐位设置 SDA 的值
        SHOU = 1;                    // 将 SCL 拉高，准备发送
        SHOU = 0;                    // 将 SCL 拉低，发送当前数据位
    }
}

/**
 * @brief 从 I2C 总线读取一个字节数据（8 位）
 * 
 * 通过 I2C 协议逐位读取一个字节的数据。
 * 
 * @param none
 * @return Data 接收到的数据（8 位）
 */
unsigned char I2C_ReadByte()
{
    unsigned char i = 0;
    unsigned char Data = 0;

    SHUJU = 1;  // 将 SDA 设置为输入模式，准备读取数据

    // 逐位读取字节
    for (i = 0; i < 8; i++)
    {
        SHOU = 1;  // 拉高 SCL，准备读取数据
        if (SHUJU == 1)  // 读取 SDA 上的电平
            Data |= (0x80 >> i);  // 如果 SDA 为高电平，设置对应的位
        SHOU = 0;  // 拉低 SCL，完成当前位的读取
    }

    return Data;  // 返回接收到的字节数据
}

/**
 * @brief 发送 ACK 或 NACK 信号
 * 
 * 根据传入的 Ack 值，发送 ACK 或 NACK 信号，
 * 用于应答或者拒绝数据传输。
 * 
 * @param Ack 传入的 ACK 或 NACK 信号（0 或 1）
 * @return none
 */
void I2C_SendAck(unsigned char Ack)
{
    SHUJU = Ack;  // 如果 Ack 为 1，则发送 ACK，若为 0，则发送 NACK
    SHOU = 1;     // 拉高 SCL，准备发送
    SHOU = 0;     // 拉低 SCL，完成 ACK 信号发送
}

/**
 * @brief 读取 ACK 信号
 * 
 * 读取从机的 ACK 信号，判断数据是否正确接收。
 * 
 * @param none
 * @return Ack 返回接收到的 ACK 信号（1 或 0）
 */
unsigned char I2C_ReadAck()
{
    unsigned char Ack = 0;

    SHUJU = 1;   // 将 SDA 设置为输入模式，准备读取 ACK
    SHOU = 1;    // 拉高 SCL，准备读取 ACK
    if (SHUJU == 1)  // 如果 SDA 为高，表示接收到 ACK
        Ack = 1;  // ACK 为 1
    SHOU = 0;    // 拉低 SCL，完成 ACK 的读取

    return Ack;  // 返回读取的 ACK 信号（1 或 0）
}
